#include "bbh_message.h"

#include "bbh_linkitem.h"
#include "bbh_outbuffer.h"
#include "bbh_thread.h"
#include "bbh_pattern.h"

struct LEVEL_TXT_S{
    const char  * t;
    const char  * t0;
} LEVEL_TEXT[] = {
    {"DEBUG",   "debug"},
    {"INFO",    "info"},
    {"NOTICE",  "notice"},
    {"WARN",    "warn"},
    {"ERROR",   "error"},
    {"FATAL",   "fatal"}
};

int  bbh_message_print(bbh_pattern_t*f, bbh_thread_t*thd, bbh_message_t*msg, const char*fmt, ...)
{
    int r;
    va_list ap;
    va_start(ap, fmt);
    r = bbh_message_vprint(f, thd, msg, fmt, ap);
    va_end(ap);

    return r;
}
int  bbh_message_vprint(bbh_pattern_t*f, bbh_thread_t*thd, bbh_message_t*msg, const char*fmt, va_list args)
{
    int                     r = 0;
    struct pattern_item_s   * item;
    //struct bbh_format_s     * f = (struct bbh_format_s *)_;
    bbh_linkitem_t          *plink;

    bbh_outbuffer_t * out = thd->msg_buf;

    out->data_len = 0;

    BBH_LINKITEM_FOR_BEGIN(&f->root, plink)

        item = ADDRESS_OF(plink, struct pattern_item_s, link_item);

        switch(item->spec[0]) {
        case 0:             // 固定串
            bbh_outbuffer_write(out, item->s, item->len);
            break;
        case 'F':           // 文件名
            bbh_outbuffer_write(out, msg->filename, msg->filename_len);
            break;
        case 'f':
            bbh_outbuffer_write(out, msg->shortname, msg->shortname_len);
            break;
        case 'U':
            bbh_outbuffer_write(out, msg->function, msg->function_len);
            break;
        case 'L':
            bbh_outbuffer_print(out, item->s, msg->line);
            break;
        case 'n':
            bbh_outbuffer_write(out, "\n", 1);// windows为\r\n
            break;
        case '%':
            bbh_outbuffer_write(out, "%", 1);
            break;
        case 'm':
            if (item->spec[1] == 's') {
                bbh_outbuffer_print(out, "%03d", (int)(msg->tv.tv_usec / 1000));
            } else {
                bbh_outbuffer_vprint(out, fmt, args);
            }
            break;
        case 'u':
            if (item->spec[1]=='s') {
                bbh_outbuffer_print(out, "%06d", (int)(msg->tv.tv_usec));
            }
            break;
        case 't':
            bbh_outbuffer_print(out, "0x%X", msg->thread_id);
            break;
        case 'T':
            bbh_outbuffer_print(out, "%lu", msg->thread_id);
            break;
        case 'c':
            break;
        case 'V':
            bbh_outbuffer_print(out, item->s, LEVEL_TEXT[msg->level].t);
            break;
        case 'v':
            bbh_outbuffer_print(out, item->s, LEVEL_TEXT[msg->level].t0);
            break;
        case 'd':
            if (item->s && item->len) {
                bbh_outbuffer_strftime(out, item->s, msg->tv.tv_sec);
            } else {
                bbh_outbuffer_strftime(out, "%F %T", msg->tv.tv_sec);
            }
            break;
        }
    BBH_LINKITEM_FOR_END
    //}

    return r; 
}

int  bbh_message_write(bbh_pattern_t*f, bbh_thread_t*thd, bbh_message_t*msg, const char*data, size_t len)
{
    int                     r;
    struct pattern_item_s    * item;
    //struct bbh_format_s     * f = (struct bbh_format_s *)_;
    bbh_linkitem_t          *plink;

    bbh_outbuffer_t * out = thd->msg_buf;

    out->data_len = 0;

    r = 0;

    BBH_LINKITEM_FOR_BEGIN(&f->root, plink)

        item = ADDRESS_OF(plink, struct pattern_item_s, link_item);

        switch(item->spec[0]) {
        case 0:             // 固定串
            bbh_outbuffer_write(out, item->s, item->len);
            break;
        case 'F':           // 文件名
            bbh_outbuffer_write(out, msg->filename, msg->filename_len);
            break;
        case 'f':
            bbh_outbuffer_write(out, msg->shortname, msg->shortname_len);
            break;
        case 'U':
            bbh_outbuffer_write(out, msg->function, msg->function_len);
            break;
        case 'L':
            bbh_outbuffer_print(out, item->s, msg->line);
            break;
        case 'n':
            bbh_outbuffer_write(out, "\n", 1);// windows为\r\n
            break;
        case '%':
            bbh_outbuffer_write(out, "%", 1);
            break;
        case 'm':
            if (item->spec[1] == 's') {
                bbh_outbuffer_print(out, "%03d", (int)(msg->tv.tv_usec / 1000));
            } else {
                bbh_outbuffer_print(out, data, len);
            }
            break;
        case 'u':
            if (item->spec[1]=='s') {
                bbh_outbuffer_print(out, "%06d", (int)(msg->tv.tv_usec));
            }
            break;
        case 't':
            bbh_outbuffer_print(out, "0x%X", msg->thread_id);
            break;
        case 'T':
            bbh_outbuffer_print(out, "%lu", msg->thread_id);
            break;
        case 'c':
            break;
        case 'V':
            bbh_outbuffer_print(out, item->s, LEVEL_TEXT[msg->level].t);
            break;
        case 'v':
            bbh_outbuffer_print(out, item->s, LEVEL_TEXT[msg->level].t0);
            break;
        case 'd':
            if (item->s && item->len) {
                bbh_outbuffer_strftime(out, item->s, msg->tv.tv_sec);
            } else {
                bbh_outbuffer_strftime(out, "%F %T", msg->tv.tv_sec);
            }
            break;
        }
    BBH_LINKITEM_FOR_END
    //}

    return r; 
}
